/*
 * 版权所有 (C) 2015 知启蒙(ZHIQIM) 保留所有权利。[遇见知启蒙，邂逅框架梦]
 * 
 * https://zhiqim.org/project/zhiqim_framework/zhiqim_httpd.htm
 *
 * Zhiqim Httpd is licensed under Mulan PSL v2.
 * You can use this software according to the terms and conditions of the Mulan PSL v2.
 * You may obtain a copy of Mulan PSL v2 at:
 *          http://license.coscl.org.cn/MulanPSL2
 * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND,
 * EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT,
 * MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE.
 * See the Mulan PSL v2 for more details.
 */
package org.zhiqim.httpd.bio;

import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.Socket;
import java.security.cert.X509Certificate;

import org.zhiqim.httpd.HttpConnection;
import org.zhiqim.httpd.HttpContext;
import org.zhiqim.httpd.HttpListener;
import org.zhiqim.httpd.HttpdConstants;
import org.zhiqim.httpd.websocket.HttpWebSocketService;
import org.zhiqim.kernel.model.maps.HashMapSS;
import org.zhiqim.kernel.util.Closes;

/**
 * HTTP连接信息类（连接即请求），包括输入输出流，实现Runnable，用于线程处理
 *
 * @version v1.0.0 @author zouzhigang 2014-3-21 新建与整理
 */
public final class HttpBioConnection implements HttpConnection, Runnable, HttpdConstants
{
    private final String connId;
    
    private final HttpListener listener;
    private final Socket socket;
    private final String remoteAddr;
    private final int remotePort;
    private final InputStream input;
    private final OutputStream output;
    
    //依次找到1.HttpHeader,2.HttpServer,3.HttpContext
    private HttpBioHeader header;
    
    //websocket
    private HttpBioWebSocket websocket;
    
    public HttpBioConnection(HttpListener listener, Socket socket, InputStream input, OutputStream output)
    {//HTTP
        this.connId = sequence.nextString();
        
        this.listener = listener;
        this.socket = socket;
        this.remoteAddr = socket.getInetAddress().getHostAddress();
        this.remotePort = socket.getPort();
        this.input = input;
        this.output = output;
        
        this.header = new HttpBioHeader(this);
    }
    
    public HttpBioConnection(HttpListener listener, Socket socket, InputStream input, OutputStream output, X509Certificate[] certs)
    {//HTTPS
        this(listener, socket, input, output);
        //用于业务再次认证
        this.header.setCertificates(certs);
    }
    
    /***********************************************************************/
    //获取连接对应的websocket属性
    /***********************************************************************/
    
    @Override /** 是否是WebSocket连接 */
    public boolean isWebSocket()
    {
        return websocket != null;
    }
    
    @Override /** 升级为WebSocket连接 */
    public void doWebSocket(HttpContext context, HashMapSS headers, HashMapSS parameters, String protocol, String sessionId, HttpWebSocketService service)
    {
        websocket = new HttpBioWebSocket(this, context, headers, parameters, protocol, sessionId, service);
        websocket.open();
    }
    
    @Override /** 开启WebSocket回调 */
    public void doWebSocketOpen()
    {
        if (websocket != null)
        {
            websocket.doOpen();
        }
    }

    /** 是否活动 */
    public boolean isActive()
    {
        return true;
    }
    
    /** 是否超时 */
    public boolean isOvertime()
    {
        return false;
    }
    
    /** 是否已关闭 */
    public boolean isClosed()
    {
        return socket.isClosed();
    }
    
    /********************************************************************************/
    //处理请求
    /********************************************************************************/

    public void run()
    {
        try
        {
            header.execute();
        }
        catch (Exception e)
        {
            close();
        }
    }
    
    /** 写入数据 */
    public void write(byte[] data) throws IOException
    {
        write(data, 0, data.length);
    }
    
    /** 写入数据 */
    public void write(byte[] data, int off, int len) throws IOException
    {
        output.write(data, off, len);
    }
    
    /** 关闭连接 */
    public void close()
    {//由sender回调
        listener.remove(this);
        
        Closes.closeIgnoreException(input, output, socket);
    }
    
    
    /***********************************************************************/
    //获取连接属性上的参数
    /***********************************************************************/
    
    @Override
    public String getId()
    {
        return connId;
    }
    
    @Override
    public HttpListener getListener()
    {
        return listener;
    }
    
    @Override
    public String getRemoteAddr()
    {
        return remoteAddr;
    }
    
    @Override
    public int getRemotePort()
    {
        return remotePort;
    }
    
    /***************************************************************************/
    //请求属性
    /***************************************************************************/
    
    public InputStream getInputStream()
    {
        return input;
    }
}
